/*************************************************************************************//*
*  作者: 邹杭特                                                                       *
*  时间: 2021-04-18                                                                   *
*  版本: master_482d3f                                                                *
*  功能:                                                                              *
*   - http 请求句柄                                                                   *
*//************************************************************************************/

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;

namespace GopeedAPI.Http
{
    public class HttpRequestInfo : IEnumerator
    {
        public string requestId;
        public string url;
        public string requestType;
        public Dictionary<string, object> form = null;
        public byte[] bytes = null;
        public string json = null;
        public RequestEvent callBack;
        public Action<float> onProgress;
        public float timeOut = -1f;
        public int retryCounter = -1;
        public object context;
        public Dictionary<string, string> headers;
        public string localPath;
        private bool m_isDone;
        public object Current => this;
        public bool isDone => m_isDone;
        public IHttpResponceInfo responceInfo { get; private set; } 
        public string MakeRequestId()
        {
            if (!string.IsNullOrEmpty(requestId))
                return requestId;
            requestId = $"{url}{requestType}";
            var dataHash = new System.Text.StringBuilder();
            if (dataHash != null)
            {
                dataHash.Append(json);
            }
            if (bytes != null)
            {
                dataHash.Append(System.Text.Encoding.UTF8.GetString(bytes).GetHashCode());
            }
            if (form != null)
            {
                foreach (var pair in form)
                {
                    dataHash.Append(pair.Value.ToString().GetHashCode());
                }
            }
            requestId += dataHash.ToString().GetHashCode();
            if (requestType != "GET")
            {
                requestId += System.Guid.NewGuid();
            }
            return requestId;
        }

        public HttpRequestInfo() { }

        public HttpRequestInfo(string url, string requestType)
        {
            this.url = url;
            this.requestType = requestType;
        }
        public static HttpRequestInfo Get(string url)
        {
            var info = new HttpRequestInfo(url, "GET");
            return info;
        }
        public static HttpRequestInfo Post(string url)
        {
            var info = new HttpRequestInfo(url, "POST");
            return info;
        }

        public bool MoveNext()
        {
            return !m_isDone;
        }

        public void Reset()
        {
            m_isDone = false;
        }

        public void Finish(IHttpResponceInfo responce)
        {
            m_isDone = true;
            responceInfo = responce;
            callBack?.Invoke(this, responce);
        }


        #region UniTask
        /// <summary>
        /// 获取UniTask异步句柄
        /// </summary>
        /// <returns></returns>
        public Awaiter GetAwaiter()
        {
            return new Awaiter(this);
        }

        /// <summary>
        /// UniTask异步句柄
        /// </summary>
        public struct Awaiter : ICriticalNotifyCompletion
        {
            private HttpRequestInfo _asyncOperation;
            private Action<HttpRequestInfo> _continuationAction;

            public Awaiter(HttpRequestInfo asyncOperation)
            {
                this._asyncOperation = asyncOperation;
                this._continuationAction = null;
            }

            public bool IsCompleted => _asyncOperation == null || _asyncOperation.isDone;

            /// <summary>
            /// 资源包获取
            /// </summary>
            /// <returns></returns>
            public IHttpResponceInfo GetResult()
            {
                IHttpResponceInfo bundle = _asyncOperation?.responceInfo;
                if (_continuationAction != null)
                {
                    _asyncOperation.callBack -= OnFinish;
                    _continuationAction = null;
                    _asyncOperation = null;
                }
                else
                {
                    _asyncOperation = null;
                }
                return bundle;
            }
            private void OnFinish(HttpRequestInfo req, IHttpResponceInfo res)
            {
                _continuationAction?.Invoke(_asyncOperation);
            }
            /// <summary>
            /// 注册完成事件
            /// </summary>
            /// <param name="continuation"></param>
            public void OnCompleted(Action continuation)
            {
                UnsafeOnCompleted(continuation);
            }
            /// <summary>
            /// 注册完成事件 [__DynamicallyInvokable]
            /// </summary>
            /// <param name="continuation"></param>
            public void UnsafeOnCompleted(Action continuation)
            {
                _continuationAction = new Action<HttpRequestInfo>((x) => { continuation?.Invoke(); });
                if(_asyncOperation.callBack == null)
                    _asyncOperation.callBack = OnFinish;
                else
                    _asyncOperation.callBack += OnFinish;
            }
        }
        #endregion UniTask

    }

    public class HttpsResponceInfo : IHttpResponceInfo
    {
        public string requestId;
        private string m_text;
        public string text => ReadText();
        public bool success { get; protected set; }
        public HttpStatusCode code { get; protected set; }
        private byte[] m_bytes;
        public byte[] bytes => ReadBytes();
        public int responseCode => (int)code;
        public bool isDone { get; private set; }

        public HttpWebResponse response;
        public HttpWebRequest request;
        public IAsyncResult operation;
        protected bool m_used;
        public float startTime;
        internal float timeOut;
        internal int retryCounter;
        internal float progress;
        private LogEvent m_logEvent;
        public HttpsResponceInfo(LogEvent logEvent)
        {
            m_logEvent = logEvent;
        }

        public string error { get; private set; }

        public void GetResponce()
        {
            if (operation == null || isDone)
                return;

            if (operation != null && !operation.IsCompleted)
            {
                success = false;
                error = "GetResponce time out!";
                return;
            }

            try
            {
                response = (HttpWebResponse)request.EndGetResponse(operation);
                success = response.StatusCode == HttpStatusCode.OK || (int)response.StatusCode == 555;
            }
            catch (WebException e)
            {
                response = (HttpWebResponse)e.Response;
                if (response != null && (int)response.StatusCode == 555)
                {
                    success = true;
                    OnLog("server return 555!");
                }
                error = e.Message;
            }
            if (response != null)
                code = response.StatusCode;
            progress = 1;
            isDone = true;
        }

        private void OnLog(string msg)
        {
            m_logEvent?.Invoke(msg);
        }

        public void WriteFile(string filePath)
        {
            if (response == null)
                return;
            if (m_used)
                return;
            m_used = true;

            if (success)
            {
                try
                {
                    //获取response的流
                    using (Stream receiveStream = response.GetResponseStream())
                    {
                        using (var ms = new System.IO.FileStream(filePath, FileMode.CreateNew, FileAccess.Write, FileShare.ReadWrite))
                        {
                            byte[] buffer = new byte[512];
                            while (true)
                            {
                                int sz = receiveStream.Read(buffer, 0, 512);
                                if (sz == 0) break;
                                ms.Write(buffer, 0, sz);
                            }
                        }
                    }
                }
                catch (Exception e)
                {
                    OnLog(requestId + "GetResponseError:" + e.Message);
                }
            }
        }

        public string ReadText()
        {
            if (response == null)
                return null;

            if (m_used)
                return m_text;

            m_used = true;

            try
            {
                //获取response的流
                using (Stream receiveStream = response.GetResponseStream())
                {
                    using (StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8))
                    {
                        m_text = readStream.ReadToEnd();
                        response.Close();
                        readStream.Close();
                    }
                }
            }
            catch (Exception e)
            {
                OnLog(requestId + "GetResponseError:" + e.Message);
            }

            return m_text;
        }

        public byte[] ReadBytes()
        {
            if (response == null)
                return null;

            if (m_used)
                return m_bytes;

            m_used = true;

            try
            {
                //获取response的流
                using (Stream receiveStream = response.GetResponseStream())
                {
                    using (MemoryStream ms = new MemoryStream())
                    {
                        byte[] buffer = new byte[512];
                        while (true)
                        {
                            int sz = receiveStream.Read(buffer, 0, 512);
                            if (sz == 0) break;
                            ms.Write(buffer, 0, sz);
                        }
                        m_bytes = ms.ToArray();
                    }
                }
            }
            catch (Exception e)
            {
                OnLog(requestId + " GetResponseError:" + e.Message);
            }
            return m_bytes;
        }

        internal void Reset()
        {
            request?.Abort();
            request = null;
            m_text = null;
            m_used = false;
            response?.Close();
            response = null;
            startTime = 0;
            isDone = false;
            progress = 0;
        }
    }
   

    public interface IHttpResponceInfo
    {
        bool success { get; }
        string text { get; }
        byte[] bytes { get; }
        int responseCode { get; }
        string error { get; }
    }
}